﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;

namespace melodyMe
{
    class lyricsManager
    {
        /// <summary>
        /// Generates required URI string and passes it to the HTTP_Response method.
        /// </summary>
        /// <param name="track">What track we want lyrics for</param>
        /// <param name="artist">The artist that wrote the track</param>
        /// <returns>All the strings for the lyrics in a string[]</returns>
        public string[] InitaliseLyricsData(string track, string artist)
        {
            try
            {
                string lyricsTrackTitle, lyricsArtistInitial, lyricsArtist;

                if (String.IsNullOrEmpty(track) || String.IsNullOrEmpty(artist)) return null;

                //Replace spaces with underscores for lyrics webrequest.
                lyricsTrackTitle = StripPunctuation(track);

                //Initial for artist catagorization.
                artist = artist.Trim();
                lyricsArtistInitial = artist.Substring(0, 1);

                //Parse Artist and trim "The " if it is present.
                if (artist.Substring(0, 3).ToLower() == "the") { artist = artist.Remove(0, 4); }
                lyricsArtist = StripPunctuation(artist);

                if (String.IsNullOrEmpty(lyricsTrackTitle) || String.IsNullOrEmpty(lyricsArtistInitial) || String.IsNullOrEmpty(lyricsArtist))
                {
                    //Terminate, one of them is broken, return null.
                    return null;
                }

                string[] lyricsArray = HTTP_Response(lyricsArtistInitial, lyricsArtist, lyricsTrackTitle);
                return lyricsArray;
            }
            catch (System.Exception) { return null; }
        }

        /// <summary>
        /// Gets the lyrics from the server.
        /// </summary>
        /// <param name="searchTitle">The string holding the Track we're searching for.</param>
        /// <returns>HTML from the target page.</returns>
        private string[] HTTP_Response(string lyricsArtistInitial, string lyricsArtist, string lyricsTrackTitle)
        {
            try
            {
                //Example string: hxxp://www.lyricsmode.com/lyrics/y/yashin/get_loose.html
                string sRequest = "http://www.lyricsmode.com/lyrics/" + lyricsArtistInitial + "/" + lyricsArtist + "/" + lyricsTrackTitle + ".html";
                sRequest = sRequest.ToLower();

                WebRequest webRequest = WebRequest.Create(sRequest);
                webRequest.Timeout = 7500;

                using (HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse())
                {
                    Stream responseStream = response.GetResponseStream();

                    string[] lyrics = GetLyrics(responseStream);
                    return lyrics;
                }
            }
            catch (WebException ex)
            {
                if (ex.Status == WebExceptionStatus.ProtocolError && ex.Response != null)
                {
                    var response = (HttpWebResponse)ex.Response;
                    if (response.StatusCode == HttpStatusCode.NotFound) //If 404'd:
                    {
                        return null;
                    }
                }

                return null;
            }
        }

        /// <summary>
        /// Parses response from HTTP and converts it into a readable format.
        /// </summary>
        /// <param name="HTTPDATA">The Stream of data from HTTP request</param>
        /// <returns>All the strings for the lyrics in a string[]</returns>
        private string[] GetLyrics(Stream HTTPDATA)
        {
            StreamReader dataReader = new StreamReader(HTTPDATA, Encoding.Default);
            string htmlString, lyricLine;

            List<string> listArray = new List<string>();

            while (HTTPDATA != null)
            {
                htmlString = dataReader.ReadLine();
                if (htmlString == null) break;

                if (htmlString.IndexOf("<div id='songlyrics_h' class='dn'>", 0, htmlString.Length) != -1)
                {
                    //Inside the lyrics HTML, start reading.
                    while (htmlString.IndexOf("</div>", 0, htmlString.Length) == -1)
                    {
                        //While it's NOT hit the end of the lyrics, keep going and add to string[]
                        htmlString = StripExcess(htmlString, null);

                        //Convert from ASCII code to Symbol, or straight add if text.
                        if (htmlString == null) { htmlString = dataReader.ReadLine();  continue; }

                        if (htmlString.IndexOf("&#", 0, htmlString.Length) != -1)
                        {
                            lyricLine = ConvertToString(htmlString, htmlString.Length);
                            listArray.Add(lyricLine);
                        }
                        else
                        {
                            listArray.Add(htmlString);
                        }

                        htmlString = dataReader.ReadLine();
                    }

                    return listArray.ToArray();
                }
            }

            //Should NOT get here. Oops. Return null I guess.
            return null;
        }

        /// <summary>
        /// Removes the HTML from the line read, and returns a 'scrubbed' string.
        /// </summary>
        /// <param name="trackString">A string passed pre-scrub with HTML tags in the formatting.</param>
        /// <param name="Overload">Additional tags that can be stripped from the line.</param>
        /// <returns>A scrubbed string</returns>
        private string StripExcess(string lyricString, string Overload)
        {
            string scrubbedString = null;
            string[] ExcessStrings = { "<div id='songlyrics_h' class='dn'>", "<br />", Overload };
            string[] stringArray = lyricString.Split(ExcessStrings, 5, StringSplitOptions.RemoveEmptyEntries);

            foreach (string s in stringArray)
            { scrubbedString += s; }

            return scrubbedString;
        }

        private string StripPunctuation(string dataString)
        {
            string scrubbedString = null;
            string[] ExcessStrings = { "'", "&", "!"};
            string[] stringArray = dataString.Split(ExcessStrings, 5, StringSplitOptions.RemoveEmptyEntries);

            foreach (string s in stringArray)
            { scrubbedString += s; }

             return scrubbedString.Replace(" ", "_");
        }

        /// <summary>
        /// Converts ASCII encoding to regular char encoding.
        /// </summary>
        /// <param name="data">data to convert</param>
        /// <param name="stringLength">length of that string</param>
        /// <returns>the lyric string in A-Z format.</returns>
        private string ConvertToString(string data, int stringLength)
        {
            string[] clippedASCII = data.Split(new string[] { "&#" }, stringLength, StringSplitOptions.RemoveEmptyEntries);
            char[] fixedChars = new char[clippedASCII.Length];

            for (int i = 0; i < fixedChars.Length; i++)
            {
                int num = Convert.ToInt32(clippedASCII[i]);
                fixedChars[i] = (char)num;
            }

            string ASCIIstring = new string(fixedChars);
            return ASCIIstring;
        }
    }
}
